﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Linq.Expressions;
using System.Data.Linq;
using System.Data.Common;
using RH.EBS.Core.Repository.Tools;
using System.Data.Entity;

namespace RH.EBS.Core.Repository.Tools.Extensions
{
    public class DbComnds
    {
        public string Sql { get; set; }
        public object[] Params { get; set; }
        public CommandType CommandType { get; set; }
    }
    public static class DbContextExtensions
    {
        static DbContextExtensions()
        {
            DbComnds = new List<DbComnds>();
        }
      
        //private static object lockObj = new object();
        //private static object lockObj2 = new object();
        //private static object lockObj3 = new object();
        //[ThreadStaticAttribute]
        public static List<DbComnds> DbComnds = new List<DbComnds>();
        public static void AddDbComnds(this DbContext dbContext, string sql, object[] param, CommandType commandType)
        {
            //lock (lockObj)
            {
                DbComnds.Add(new DbComnds() { Sql = sql, Params = param, CommandType = commandType });
            }
        }

        public static List<DbComnds> GetDbComnds(this DbContext dbContext)
        {
            //lock (lockObj2)
            {
                return DbComnds;
            }
        }

        public static void ClearAll(this DbContext dbContext)
        {
            //lock (lockObj3)
            {
                DbComnds = new List<DbComnds>();
            }
        }
    }
    /// <summary>
    /// DbSet扩展
    /// </summary>
    public static class DbSetExtensions
    {
        /// <summary>
        /// 批量删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbSet">表</param>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>影响的行数</returns>
        public static int Delete<T>(this DbContext dbContext, Expression<Func<T, bool>> predicate) where T : class
        {
            //获取表名
            string tableName = typeof(T).Name;//.Context.Mapping.GetTable(typeof(T)).TableName;

            //查询条件表达式转换成SQL的条件语句
            ConditionBuilder builder = new ConditionBuilder();
            builder.Build(predicate.Body);
            string sqlCondition = builder.Condition;

            //SQL命令
            string commandText = string.Format("DELETE FROM {0} WHERE {1}", tableName, sqlCondition);

            //获取SQL参数数组 
            var args = builder.Arguments;

            //执行
            return dbContext.Database.ExecuteSqlCommand(commandText, args);
        }

        /// <summary>
        /// 批量更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table">表</param>
        /// <param name="predicate">查询条件表达式</param>
        /// <param name="updater">更新表达式</param>
        /// <returns>影响的行数</returns>
        public static int Update<T>(this Table<T> table, Expression<Func<T, bool>> predicate, Expression<Func<T, T>> updater) where T : class
        {
            //获取表名
            string tableName = table.Context.Mapping.GetTable(typeof(T)).TableName;
            DbCommand command = table.Context.GetCommand(table.Where(predicate));
            string sqlCondition = command.CommandText;
            sqlCondition = sqlCondition.Substring(sqlCondition.LastIndexOf("WHERE ", StringComparison.InvariantCultureIgnoreCase) + 6);

            //获取Update的赋值语句
            var updateMemberExpr = (MemberInitExpression)updater.Body;
            var updateMemberCollection = updateMemberExpr.Bindings.Cast<MemberAssignment>().Select(c =>
            {
                var p = command.CreateParameter();
                p.ParameterName = c.Member.Name;
                p.Value = ((ConstantExpression)c.Expression).Value;
                return p;
            })
            .ToArray();

            string sqlUpdateBlock = string.Join(", ", updateMemberCollection.Select(c => string.Format("[{0}]=@{0}", c.ParameterName)).ToArray());

            //SQL命令
            string commandText = string.Format("UPDATE {0} SET {1} FROM {0} AS t0 WHERE {2}", tableName, sqlUpdateBlock, sqlCondition);

            //获取SQL参数数组 (包括查询参数和赋值参数)
            command.Parameters.AddRange(updateMemberCollection);
            command.CommandText = commandText;

            //执行 
            try
            {
                if (command.Connection.State != ConnectionState.Open)
                {
                    command.Connection.Open();
                }
                return command.ExecuteNonQuery();
            }
            finally
            {
                command.Connection.Close();
                command.Dispose();
            }
        }

        /// <summary>
        /// 批量更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbContext">表</param>
        /// <param name="predicate">查询条件表达式</param>
        /// <param name="updater">更新表达式</param>
        /// <returns>影响的行数</returns>
        public static int Update<T>(this DbContext dbContext, Expression<Func<T, bool>> predicate, Expression<Func<T, T>> updater, bool isSave = true) where T : class
        {
            //获取表名
            string tableName = typeof(T).Name;

            //查询条件表达式转换成SQL的条件语句
            ConditionBuilder builder = new ConditionBuilder();
            builder.Build(predicate.Body);
            string sqlCondition = builder.Condition;

            //获取Update的赋值语句
            var updateMemberExpr = (MemberInitExpression)updater.Body;
            var updateMemberCollection = updateMemberExpr.Bindings.Cast<MemberAssignment>().Select(c => new
            {
                Name = c.Member.Name,
                Value = Expression.Lambda(c.Expression).Compile().DynamicInvoke()// ((ConstantExpression)c.Expression).Value
            });

            int i = builder.Arguments.Length;
            string sqlUpdateBlock = string.Join(", ", updateMemberCollection.Select(c => string.Format("[{0}]={1}", c.Name, "{" + (i++) + "}")).ToArray());

            //SQL命令
            string commandText = string.Format("UPDATE {0} SET {1} WHERE {2}", tableName, sqlUpdateBlock, sqlCondition);

            //获取SQL参数数组 (包括查询参数和赋值参数)
            var args = builder.Arguments.ToList();
            args.AddRange((updateMemberCollection.Select(c => c.Value)).ToList());
            if (!isSave)
            { dbContext.AddDbComnds(commandText, args.ToArray(), CommandType.Text); }
            //执行
            return isSave ? dbContext.Database.ExecuteSqlCommand(commandText, args.ToArray()) : 0;
        }

        //public static T Include<T, TSub>(this DbContext dbContext, Expression<Func<T, bool>> predicate, Expression<Func<T, TSub, bool>> relapredicate)
        //    where T : class
        //    where TSub : class
        //{

        //    return null;
        //}

        public static DataSet ExecuteDataSet(this DbContext dbContext, string sql, params DbParameter[] dbParameters)
        {
            DataSet ds = new DataSet();
            var conn = dbContext.Database.Connection;
            var dbCdm = conn.CreateCommand();
            dbCdm.CommandText = sql;
            foreach (var p in dbParameters)
            {
                dbCdm.Parameters.Add(p);
            }
            DbDataAdapter adapter = DbProviderFactories.GetFactory(conn).CreateDataAdapter(); ;
            adapter.SelectCommand = dbCdm;
            adapter.Fill(ds);
            return ds;
        }


        public static DataSet ExecuteProcDataSet(this DbContext dbContext, string sql, params DbParameter[] dbParameters)
        {
            DataSet ds = new DataSet();
            var conn = dbContext.Database.Connection;
            var dbCdm = conn.CreateCommand();
            dbCdm.CommandText = sql;
            dbCdm.CommandType = CommandType.StoredProcedure;
            if (dbParameters != null && dbParameters.Length > 0)
            {
                foreach (var p in dbParameters)
                {
                    dbCdm.Parameters.Add(p);
                }
            }
            DbDataAdapter adapter = DbProviderFactories.GetFactory(conn).CreateDataAdapter(); ;
            adapter.SelectCommand = dbCdm;
            adapter.Fill(ds);
            return ds;
        }

        public static int ExecuteSql(this DbContext dbContext, string sql)
        {
            
            var conn = dbContext.Database.Connection;
            var dbCdm = conn.CreateCommand();
            dbCdm.CommandText = sql;
            dbCdm.CommandType = CommandType.Text;
            conn.Open();
            int i= dbCdm.ExecuteNonQuery();
            conn.Close();
            return i;
        }


    }
}
